---
id: dbcontext-filter
title: 9.23 实体/全局查询筛选器
sidebar_label: 9.23 实体/全局查询筛选器
---

## 9.23.1 查询筛选器

通常，我们系统中有一些维护字段，如 `IsDeleted` 字段，这个字段用来标识用户已经删除的数据，那么我们需要每次查询数据的时候带上这个字段，避免查询出不该出现的数据。

`Fur` 提供非常灵活方便的全局查询筛选器，能够应用到每一次查询中。

## 9.23.2 多种筛选器配置

### 9.23.2.1 单表筛选器

单表筛选器就是只针对特定实体进行筛选操作，使用简单，只需要在继承 `IEntityTypeBuilder<TEntity>` 接口并实现即可，如：

```cs {8,24}
using Fur.DatabaseAccessor;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using System;

namespace Fur.Core
{
    public class Person : Entity, IEntityTypeBuilder<Person>
    {
        public Person()
        {
            CreatedTime = DateTime.Now;
            IsDeleted = false;
        }

        public string Name { get; set; }

        public int Age { get; set; }

        public string Address { get; set; }

        public void Configure(EntityTypeBuilder<Person> entityBuilder, DbContext dbContext, Type dbContextLocator)
        {
            entityBuilder.HasQueryFilter(u => !u.IsDeleted);
        }
    }
}
```

### 9.23.2.2 全局筛选器

全局筛选器可以配置所有实体应用筛选器中，无需一个一个去配置。使用方法稍微有些复杂，需要动态构建 `Lambda` 表达式。

实现全局筛选器依赖于 `IModelBuilderFilter` 接口，该接口提供两个方法：

- `OnCreating`：实体构建之前
- `OnCreated`：实体构建之后

通过实现这两个方法即可配置全局过滤器，如：

```cs {10,18-19,21,24}
using Fur.DatabaseAccessor;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using System;
using System.Linq.Expressions;

namespace Fur.EntityFramework.Core
{
    [AppDbContext("Sqlite3ConnectionString")]
    public class FurDbContext : AppDbContext<FurDbContext>, IModelBuilderFilter<MasterDbContextLocator>
    {
        public FurDbContext(DbContextOptions<FurDbContext> options) : base(options)
        {
        }

        public void OnCreated(ModelBuilder modelBuilder, EntityTypeBuilder entityBuilder, DbContext dbContext, Type dbContextLocator)
        {
            var expression = BuilderIsDeleteLambdaExpression(entityBuilder);
            if (expression == null) return;

            entityBuilder.HasQueryFilter(expression);
        }

        public void OnCreating(ModelBuilder modelBuilder, EntityTypeBuilder entityBuilder, DbContext dbContext, Type dbContextLocator)
        {
        }

        /// <summary>
        /// 构建 u => EF.Property<bool>(u, "IsDeleted") == false 表达式
        /// </summary>
        /// <param name="entityBuilder"></param>
        /// <returns></returns>
        private LambdaExpression BuilderIsDeleteLambdaExpression(EntityTypeBuilder entityBuilder)
        {
            // 获取实体构建器元数据
            var metadata = entityBuilder.Metadata;
            if (metadata.FindProperty(nameof(Entity.IsDeleted)) == null) return default;

            // 创建表达式元素
            var parameter = Expression.Parameter(metadata.ClrType, "u");
            var properyName = Expression.Constant(nameof(Entity.IsDeleted));
            var propertyValue = Expression.Constant(false);

            // 构建表达式 u => EF.Property<bool>(u, "IsDeleted") == false
            var expressionBody = Expression.Equal(Expression.Call(typeof(EF), nameof(EF.Property), new[] { typeof(bool) }, parameter, properyName), propertyValue);
            var expression = Expression.Lambda(expressionBody, parameter);
            return expression;
        }
    }
}
```

:::note 小建议

如果对动态构建 `LambdaExpression` 不熟悉的朋友，可以使用 `System.Linq.Dynamic.Core` 包 [https://github.com/zzzprojects/System.Linq.Dynamic.Core](https://github.com/zzzprojects/System.Linq.Dynamic.Core)

:::

## 9.23.3 反馈与建议

:::note 与我们交流

给 Fur 提 [Issue](https://gitee.com/monksoul/Fur/issues/new?issue)。

:::
